#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
天翼云盘SDK工具模块
包含公共方法：文件大小格式化、时间格式化、签名生成、加密解密等
"""

import hashlib
import hmac
import time
import uuid
import re
import binascii
import random
from typing import Dict, Optional
from Crypto.PublicKey import RSA
from Crypto.Cipher import PKCS1_v1_5, AES
from Crypto.Util.Padding import pad

# 常量定义
APP_ID = "8025431004"
VERSION = "6.2"
PC = "TELEPC"
CHANNEL_ID = "web_cloud.189.cn"


class FormatUtils:
    """格式化工具类"""
    
    @staticmethod
    def format_size(size: int) -> str:
        """格式化文件大小"""
        if size < 1024:
            return f"{size} B"
        elif size < 1024 * 1024:
            return f"{size / 1024:.1f} KB"
        elif size < 1024 * 1024 * 1024:
            return f"{size / (1024 * 1024):.1f} MB"
        else:
            return f"{size / (1024 * 1024 * 1024):.1f} GB"
    
    @staticmethod
    def format_time(timestamp: str) -> str:
        """格式化时间"""
        try:
            if len(timestamp) == 13:  # 毫秒时间戳
                timestamp = timestamp[:10]
            time_obj = time.localtime(int(timestamp))
            return time.strftime("%Y-%m-%d %H:%M", time_obj)
        except:
            return timestamp


class TimeUtils:
    """时间工具类"""
    
    @staticmethod
    def timestamp() -> int:
        """获取时间戳(毫秒)"""
        return int(time.time() * 1000)
    
    @staticmethod
    def get_http_date_str() -> str:
        """获取HTTP规范时间"""
        return time.strftime('%a, %d %b %Y %H:%M:%S GMT', time.gmtime())


class ClientUtils:
    """客户端工具类"""
    
    @staticmethod
    def client_suffix() -> Dict[str, str]:
        """客户端后缀参数"""
        rand_num = random.randint(10000, 99999)
        rand_num2 = random.randint(1000000000, 9999999999)
        return {
            "clientType": PC,
            "version": VERSION,
            "channelId": CHANNEL_ID,
            "rand": f"{rand_num}_{rand_num2}"
        }


class CryptoUtils:
    """加密工具类"""
    
    @staticmethod
    def rsa_encrypt(public_key: str, orig_data: str) -> str:
        """RSA加密用户名密码"""
        try:
            # 处理公钥格式
            if not public_key.startswith('-----BEGIN'):
                public_key = f"-----BEGIN PUBLIC KEY-----\n{public_key}\n-----END PUBLIC KEY-----"
            
            rsa_key = RSA.import_key(public_key)
            cipher = PKCS1_v1_5.new(rsa_key)
            encrypted = cipher.encrypt(orig_data.encode())
            # 转换为大写十六进制字符串
            return binascii.hexlify(encrypted).decode().upper()
        except Exception as e:
            print(f"RSA加密失败: {e}")
            return ""
    
    @staticmethod
    def aes_ecb_encrypt(data: str, key: str) -> str:
        """AES ECB加密params"""
        try:
            # 确保密钥长度为16字节
            key_bytes = key.encode()[:16]
            if len(key_bytes) < 16:
                key_bytes = key_bytes.ljust(16, b'\0')
            
            cipher = AES.new(key_bytes, AES.MODE_ECB)
            padded_data = pad(data.encode(), AES.block_size)
            encrypted = cipher.encrypt(padded_data)
            return binascii.hexlify(encrypted).decode().upper()
        except Exception as e:
            print(f"AES加密失败: {e}")
            return ""


class SignatureUtils:
    """签名工具类"""
    
    @staticmethod
    def signature_of_hmac(session_secret: str, session_key: str, operate: str, 
                         full_url: str, date_of_gmt: str, params: str = "") -> str:
        """HMAC签名"""
        url_path = re.search(r'://[^/]+((/[^/\s?#]+)*)', full_url).group(1)
        data = f"SessionKey={session_key}&Operate={operate}&RequestURI={url_path}&Date={date_of_gmt}"
        if params:
            data += f"&params={params}"
        
        signature = hmac.new(
            session_secret.encode(), 
            data.encode(), 
            hashlib.sha1
        ).hexdigest().upper()
        return signature
    
    @staticmethod
    def signature_header(url: str, method: str, token_info: Dict, params: str = "", 
                        is_family: bool = False) -> Dict[str, str]:
        """生成签名头"""
        if not token_info:
            return {}
        
        date_of_gmt = TimeUtils.get_http_date_str()
        session_key = token_info.get('sessionKey', '')
        session_secret = token_info.get('sessionSecret', '')
        
        if is_family:
            session_key = token_info.get('familySessionKey', '')
            session_secret = token_info.get('familySessionSecret', '')
        
        return {
            "Date": date_of_gmt,
            "SessionKey": session_key,
            "X-Request-ID": str(uuid.uuid4()),
            "Signature": SignatureUtils.signature_of_hmac(
                session_secret, session_key, method, url, date_of_gmt, params
            )
        }
    
    @staticmethod
    def encrypt_params(params: Dict[str, str], token_info: Dict, is_family: bool = False) -> str:
        """加密参数"""
        if not token_info or not params:
            return ""
        
        session_secret = token_info.get('sessionSecret', '')
        if is_family:
            session_secret = token_info.get('familySessionSecret', '')
        
        # 将参数编码为URL格式
        param_str = '&'.join([f"{k}={v}" for k, v in params.items()])
        return CryptoUtils.aes_ecb_encrypt(param_str, session_secret)


class CacheUtils:
    """缓存工具类"""
    
    @staticmethod
    def is_cache_valid(cache_time: float, timeout: int = 300) -> bool:
        """检查缓存是否有效"""
        return time.time() - cache_time < timeout
    
    @staticmethod
    def get_cache_key(folder_id: str, is_family: bool) -> str:
        """获取缓存键"""
        return f"{folder_id}_{is_family}"


# 便捷导入
__all__ = [
    'FormatUtils',
    'TimeUtils', 
    'ClientUtils',
    'CryptoUtils',
    'SignatureUtils',
    'CacheUtils'
]